package org.xlp.base.application.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xlp.base.application.base.Prefix;
import org.xlp.javabean.JavaBeanPropertiesDescriptor;
import org.xlp.javabean.MethodException;
import org.xlp.javabean.PropertyDescriptor;
import org.xlp.javabean.convert.mapandbean.MapValueProcesser;
import org.xlp.javabean.processer.ValueProcesser;
import org.xlp.utils.XLPPackingTypeUtil;
import org.xlp.utils.XLPStringUtil;

import javax.annotation.Resource;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Description: 应用配置文件操作工具类
 * <br/>date: 2024/11/22 15:51
 *
 * @version 1.0
 * @author: xlp
 */
public class ApplicationPropertiesUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationPropertiesUtils.class);

    private static volatile Properties applicationProperties;

    private static  final ValueProcesser VALUE_PROCESSER = new MapValueProcesser();

    /**
     * 应用配置文件名称
     */
    private static final String APPLICATION_PROPERTIES_FILE_NAME = "application.properties";

    /**
     * 缓存单例bean
     */
    private static final Map<Class<?>, Object> SINGLE_BEAN_MAP = new HashMap<>();

    /**
     * 获取应用配置文件Properties对象
     * @return
     */
    public static Properties getApplicationProperties(){
        if (applicationProperties != null) return applicationProperties;
        synchronized (ApplicationPropertiesUtils.class){
            if(applicationProperties == null){
                applicationProperties = new Properties();
                InputStream inputStream = ApplicationPropertiesUtils.class.getClassLoader()
                        .getResourceAsStream(APPLICATION_PROPERTIES_FILE_NAME);
                if (inputStream != null) {
                    applicationProperties = PropertiesFileReaderUtils.load(inputStream);
                }
                File file = new File(ApplicationUtils.getConfigBaseDir(), APPLICATION_PROPERTIES_FILE_NAME);
                if (file.isFile()){
                    applicationProperties.putAll(PropertiesFileReaderUtils
                            .loadFromAbsolutePath(file.getAbsolutePath()));
                }
            }
        }
        return applicationProperties;
    }

    /**
     * 根据bean类型，并使用配置文件生成一个bean对象
     * @param cs
     * @param <T>
     * @return
     * @throws Exception 假如bean实例化，则抛出该异常
     */
    public static <T> T toBean(Class<T> cs) throws Exception {
        T bean = cs.newInstance();
        initBean(bean);
        return bean;
    }

    /**
     * 根据bean类型，并使用配置文件生成一个单例bean对象
     * @param cs
     * @param <T>
     * @return
     * @throws Exception 假如bean实例化，则抛出该异常
     */
    @SuppressWarnings("unchecked")
    public static <T> T toSingleBean(Class<T> cs) throws Exception {
        Object o = SINGLE_BEAN_MAP.get(cs);
        if (o != null) return (T) o;
        synchronized (ApplicationPropertiesUtils.class){
            o = SINGLE_BEAN_MAP.get(cs);
            if (o == null) {
                o = toBean(cs);
                SINGLE_BEAN_MAP.put(cs, o);
            }
        }
        return (T) o;
    }

    /**
     * 初始化bean
     * @param bean
     * @param <T>
     */
    public static <T> void initBean(T bean){
       initBean(bean, null);
    }

    /**
     * 初始化bean
     * @param bean bean对象（可能是代理对象）
     * @param cs 实际类型
     * @param <B>
     * @param <T>
     */
    @SuppressWarnings("unchecked")
    public static <B, T> void initBean(B bean, Class<T> cs){
        if (bean == null) return;
        cs = (cs == null ? (Class<T>) bean.getClass() : cs);
        Prefix prefix = cs.getAnnotation(Prefix.class);
        //前缀
        String pre = prefix == null ? "" : prefix.value() + ".";
        JavaBeanPropertiesDescriptor<T> jbp = new JavaBeanPropertiesDescriptor<>(cs);
        PropertyDescriptor<T>[] pds = jbp.getPdsWithAnnotation(Resource.class);
        for (PropertyDescriptor<T> pd : pds) {
            Class<?> fcs = pd.getFiledClassType();
            //判断是否是基本类型，是则在处理
            if (isBasicType(fcs)){
                Resource resource = pd.getFieldAnnotation(Resource.class);
                String name = resource.name();
                name  = XLPStringUtil.isEmpty(name) ? pd.getFieldName() : name;
                String property = getApplicationProperties().getProperty(pre + name);
                Object value = property;
                if (!XLPStringUtil.isEmpty(property)){
                    value = VALUE_PROCESSER.processValue(pd.getFiledClassType(), value);
                    try {
                        pd.executeWriteMethod((T)bean, value);
                    } catch (MethodException e) {
                        if (LOGGER.isWarnEnabled()) {
                            LOGGER.error("设置" + cs.getName() + "初始化【" + name + "字段失败", e);
                        }
                    }
                }
            }
        }
    }

    /**
     * 判断是否是基本类型
     * @param fcs
     * @return true： 是，false：不是
     */
    private static boolean isBasicType(Class<?> fcs) {
        return fcs.equals(String.class) || XLPPackingTypeUtil.isRawNumberType(fcs)
                || XLPPackingTypeUtil.isPackingNumberType(fcs)
                || XLPPackingTypeUtil.isOtherRawOrPackingType(fcs);
    }
}
